package com.example.pacs.dicom.server.cstoresup;

import com.example.pacs.dicom.server.cfind.MWLCFindSUP;
import com.example.pacs.dicom.server.cmove.CMOVESUP;
import lombok.extern.slf4j.Slf4j;
import org.dcm4che3.net.*;
import org.dcm4che3.net.service.DicomServiceRegistry;
import org.springframework.util.StringUtils;

import java.util.concurrent.Executors;

/**
 * 定义一个DICOM服务器,在项目启动时加载到IOC容器中
 */
@Slf4j
public class DicomServer {

    private final ApplicationEntity applicationEntity = new ApplicationEntity("*");

    private final Connection connection = new Connection();

    private final Device device = new Device("storescp");

    private final SUPCStoreServiceImpl storeService;

    private final MWLCFindSUP mwlcFindSUP;

    private final CMOVESUP cmovesup;

    public DicomServer (SUPCStoreServiceImpl storeService, MWLCFindSUP mwlcFindSUP, CMOVESUP cmovesup) {
        this.storeService = storeService;
        this.mwlcFindSUP = mwlcFindSUP;
        this.cmovesup = cmovesup;
        // 给设备添加注册的服务端
        device.setDimseRQHandler(createServiceRegistry());
        // 设备添加连接,ae和连接策略
        device.addConnection(connection);
        device.addApplicationEntity(applicationEntity);
        AssociationHandler associationHandler = new AssociationHandler();
        device.setAssociationHandler(associationHandler);
        // 设置服务端是否可以接受连接
        applicationEntity.setAssociationAcceptor(true);
        // 服务端添加连接
        applicationEntity.addConnection(connection);
    }

    /**
     * 初始化DICOM server方法
     * @param pacsStorageDir dcm文件存放的位置
     * @param pacsAeTitle application entity title
     * @param pacsPort 监听端口
     * @param aeHost 应用host
     * @return DICOM server
     */
    public static DicomServer init(String aeHost, String pacsStorageDir, String pacsAeTitle, int pacsPort, SUPCStoreServiceImpl storeService, MWLCFindSUP mwlcFindSUP, CMOVESUP cmovesup) {
        log.info("初始化DICOM server,storageDir:{}, aeTitle:{}, ports:{}", pacsStorageDir, pacsAeTitle, pacsPort);
        DicomServer dicomServer = null;
        try {
            dicomServer = new DicomServer(storeService, mwlcFindSUP, cmovesup);
            if (!StringUtils.isEmpty(aeHost)) {
                dicomServer.connection.setHostname(aeHost);
            }
            // 配置DICOM server的监听端口
            dicomServer.connection.setPort(pacsPort);
            configConnection(dicomServer.connection);
            // 设置DICOM server的应用名称
            dicomServer.applicationEntity.setAETitle(pacsAeTitle);
            // 描述DICOM server的传输能力,这里声明为SCP标识这是一个服务端,支持所有的SOP CLASS和所有的编码格式
            dicomServer.applicationEntity.addTransferCapability(new TransferCapability(null, "*", TransferCapability.Role.SCP, "*"));
            // 配置服务端设备需要的线程池
            dicomServer.device.setExecutor(Executors.newCachedThreadPool());
            dicomServer.device.setScheduledExecutor(Executors.newScheduledThreadPool(10));
            dicomServer.device.bindConnections();
        } catch (Exception e) {
            log.error("初始化DICOM server异常,错误信息:" + e.getMessage(), e);
        }
        return dicomServer;
    }

    /**
     * 配置连接的默认参数
     */
    private static void configConnection(Connection connection) {
        connection.setReceivePDULength(Connection.DEF_MAX_PDU_LENGTH);
        connection.setSendPDULength(Connection.DEF_MAX_PDU_LENGTH);
        connection.setMaxOpsInvoked(0);
        connection.setMaxOpsPerformed(0);
    }

    /**
     * 注册服务端
     */
    private DicomServiceRegistry createServiceRegistry() {
        DicomServiceRegistry registry = new DicomServiceRegistry();
        // 这里注册的实例必须从IOC容器中获取
        registry.addDicomService(storeService);
        registry.addDicomService(this.mwlcFindSUP);
        registry.addDicomService(this.cmovesup);
        device.setDimseRQHandler(registry);
        return registry;
    }
}
